package gmu.swe.project.io;

import gmu.swe.project.registry.RegistryInfo;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.CharacterData;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * Handles the parsing of the XML file used for configuration.
 * 
 * Current design on the configuration file:
 * <?xml version="1.0"?>
 * <config>
 * 	<!--IP Address of this server - whatever kind it is -->
 * 	<ip_address>192.168.10.3</ip_address>
 *  <tracker>
 * 		<!-- Port that the tracker will listen on for peers -->
 * 		<listening_port>10398</listening_port>
 *  </tracker>
 *  <peer>
 * 		<!-- Directory of shared files -->
 * 		<shared_file_directory>C:/Christina/Documents/Temp</shared_file_directory>
 *  </peer>
 * 	<!-- Registry servers -->
 * 	<registries>
 *		<registry>
 *			<svr_id>A</svr_id>
 *			<svr_ip_address>192.168.10.2</svr_ip_address>
 *			<port>12345</port>
 *		</registry>
 *		<registry>
 *			<svr_id>A</svr_id>
 *			<svr_ip_address>192.168.10.3</svr_ip_address>
 *			<port>23456</port>
 *		</registry>
 *	</registries>
 * </config>
 * 
 * @author Christina Bradbury
 *
 */
public class ConfigFileParser {
	
	private String listeningPort = "";
	private String ipAddress = "";
	private String sharedDirectory = "";
	private Integer peerInterval;
	//if we use a list here we can add dir servers without changing code.
	private ArrayList<RegistryInfo> registryServers = new ArrayList<RegistryInfo>();

	/** Create a new ConfigFileParser **/
	public ConfigFileParser(String file) {

		DocumentBuilder docBuilder = null;
		Document doc = null;
		DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
		
		File newFile = new File(file);
		
		try {
			//create a new DocumentBuilder and parse the XML File
			docBuilder = docBuilderFactory.newDocumentBuilder();
			doc = docBuilder.parse(newFile);
			doc.getDocumentElement().normalize();
			
			//Read the nodes to retrieve the peer_registration_port of this client.
			NodeList regSockets = doc.getElementsByTagName("listening_port");
			//there should only be one socket port so we don't need to loop
			Element regSocket = (Element)regSockets.item(0);
			StringBuffer buffer = new StringBuffer();
			for (Node child = regSocket.getFirstChild(); child != null; child = child.getNextSibling()) {
				if (child instanceof CharacterData) {
					CharacterData data = (CharacterData) child;
						buffer.append(data.getData());
				}
			}
			this.listeningPort = buffer.toString().trim();
		
			//Read the nodes to retrieve the IP Address of this client.
			NodeList ipNodes = doc.getElementsByTagName("ip_address");
			//there should only be one ip address so we don't need to loop
			Element ipNode = (Element)ipNodes.item(0);
			buffer = new StringBuffer();
			for (Node child = ipNode.getFirstChild(); child != null; child = child.getNextSibling()) {
				if (child instanceof CharacterData) {
					CharacterData data = (CharacterData) child;
						buffer.append(data.getData());
				}
			}
			this.ipAddress = buffer.toString().trim();
		
			//Read the nodes to retrieve the peer interval.
			NodeList pIntervalNodes = doc.getElementsByTagName("peer_interval");
			//there should only be one ip address so we don't need to loop
			Element pIntervalNode = (Element)pIntervalNodes.item(0);
			buffer = new StringBuffer();
			for (Node child = pIntervalNode.getFirstChild(); child != null; child = child.getNextSibling()) {
				if (child instanceof CharacterData) {
					CharacterData data = (CharacterData) child;
						buffer.append(data.getData());
				}
			}
			this.peerInterval = Integer.valueOf(buffer.toString().trim());
			
			//Read the nodes to retrieve the shared file directory of this client.
			NodeList dirNodes = doc.getElementsByTagName("shared_file_directory");
			//there should only be one directory so we don't need to loop
			Element dirNode = (Element)dirNodes.item(0);
			buffer = new StringBuffer();
			for (Node child = dirNode.getFirstChild(); child != null; child = child.getNextSibling()) {
				if (child instanceof CharacterData) {
					CharacterData data = (CharacterData) child;
						buffer.append(data.getData());
				}
			}
			this.sharedDirectory = buffer.toString().trim();
			
			
			//Read the nodes to get the info of the Registry servers
			String id = "";
			String ip = "";
			String port = "";
			NodeList regNodes = doc.getElementsByTagName("registry");
			int totalRegs = regNodes.getLength();
			for(int i=0; i<totalRegs; i++){
				Node regNode = (Node)regNodes.item(i);
				buffer = new StringBuffer();
				if(regNode.getNodeType() == Node.ELEMENT_NODE) {
					Element regElement = (Element)regNode;
					
					NodeList nodeList = regElement.getElementsByTagName("svr_id");
					Element ipElement = (Element)nodeList.item(0);
					NodeList textList = ipElement.getChildNodes();
					id = ((Node)textList.item(0)).getNodeValue().trim();
					
					nodeList = regElement.getElementsByTagName("svr_ip_address");
					ipElement = (Element)nodeList.item(0);
					textList = ipElement.getChildNodes();
					ip = ((Node)textList.item(0)).getNodeValue().trim();
					
					nodeList = regElement.getElementsByTagName("port");
					ipElement = (Element)nodeList.item(0);
					textList = ipElement.getChildNodes();
					port = ((Node)textList.item(0)).getNodeValue().trim();
				}
				this.addRegistryServer(id, ip,new Integer(port));
			}
		} catch(ParserConfigurationException pcex) {
			//do something
			System.out.println(pcex.getMessage());
		} catch(IOException ioex) {
			//do something
			System.out.println(ioex.getMessage());
		} catch(SAXException saxex) {
			//do something
			System.out.println(saxex.getMessage());
		}
		
	}

	/** Accessors **/
	public String getIpAddress() {
		return ipAddress;
	}
	public void setIpAddress(String ipAddress) {
		this.ipAddress = ipAddress;
	}
	public String getSharedDirectory() {
		return sharedDirectory;
	}
	public void setSharedDirectory(String sharedDirectory) {
		this.sharedDirectory = sharedDirectory;
	}
	public ArrayList<RegistryInfo> getRegistryServers() {
		return registryServers;
	}
	public void setRegistryServers(ArrayList<RegistryInfo> registryServers) {
		this.registryServers = registryServers;
	}
	public void addRegistryServer(String id, String serverIP, Integer port) {
		RegistryInfo info = new RegistryInfo();
		info.setId(id);
		info.setIpAddress(serverIP);
		info.setPort(port);
		this.registryServers.add(info);
	}
	public String getListeningPort() {
		return listeningPort;
	}
	public void setListeningPort(String listeningPort) {
		this.listeningPort = listeningPort;
	}

	public Integer getPeerInterval() {
		return peerInterval;
	}

	public void setPeerInterval(Integer peerInterval) {
		this.peerInterval = peerInterval;
	}		
}